//css_dbg /t:winexe;
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Reflection;
using CSScriptLibrary;

public interface ITextCapitalizer
{
	string ToUpper(string text);
	string ToLower(string text);
}

public interface ITextProcessor
{
	string Process(string str);
}

namespace Scripting
{
    public class Form1 : System.Windows.Forms.Form
    {
        static string originalText = "The quick brown fox jumps over the lazy dog.";
        static string classlessTemplate =
@"public static string Process(string str)
{
    string retval = str;

    //replace the following line with your code 
    retval = ""\t"" + retval;
                                        
    return retval;
}";
        static string processTemplate =
@"using System;
                                        
public class Script : MarshalByRefObject
{
    public string Process(string str)
    {
        string retval = str;

       //replace the following line with your code 
       retval = ""\t"" + retval;
                                        
       return retval;
    }
}";
        static string capitalizeTemplate = 
@"using System;

public class Script : MarshalByRefObject, ITextCapitalizer
{
    public string ToUpper(string text)
    {
        return text.ToUpper();
    }
    public string ToLower(string text)
    {
        return text.ToLower();
    }
}";
        private System.Windows.Forms.TextBox textBoxText;
        private System.Windows.Forms.TextBox textBoxScript;
        private System.Windows.Forms.Button undoBtn;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Button toUpperBtn;
        private System.Windows.Forms.Button processBtn;
        private System.Windows.Forms.CheckBox remoteCheckBox;
        private GroupBox groupBox1;
        private System.ComponentModel.BackgroundWorker backgroundWorker1;
        private Button toLowerBtn;
        private RadioButton defProcessBtn;
        private RadioButton defCapitalizeBtn;
        private RadioButton defClasslessButton;
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            InitializeComponent();
            textBoxText.Text = originalText;
            defProcessBtn_Click(null, null);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        private void InitializeComponent()
        {
            this.textBoxText = new System.Windows.Forms.TextBox();
            this.textBoxScript = new System.Windows.Forms.TextBox();
            this.undoBtn = new System.Windows.Forms.Button();
            this.processBtn = new System.Windows.Forms.Button();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.toUpperBtn = new System.Windows.Forms.Button();
            this.remoteCheckBox = new System.Windows.Forms.CheckBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.defClasslessButton = new System.Windows.Forms.RadioButton();
            this.defCapitalizeBtn = new System.Windows.Forms.RadioButton();
            this.defProcessBtn = new System.Windows.Forms.RadioButton();
            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.toLowerBtn = new System.Windows.Forms.Button();
            this.groupBox1.SuspendLayout();
            this.SuspendLayout();
            // 
            // textBoxText
            // 
            this.textBoxText.AcceptsReturn = true;
            this.textBoxText.AcceptsTab = true;
            this.textBoxText.Location = new System.Drawing.Point(0, 344);
            this.textBoxText.Multiline = true;
            this.textBoxText.Name = "textBoxText";
            this.textBoxText.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.textBoxText.Size = new System.Drawing.Size(568, 112);
            this.textBoxText.TabIndex = 0;
            this.textBoxText.TabStop = false;
            this.textBoxText.WordWrap = false;
            // 
            // textBoxScript
            // 
            this.textBoxScript.AcceptsReturn = true;
            this.textBoxScript.AcceptsTab = true;
            this.textBoxScript.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
            this.textBoxScript.Location = new System.Drawing.Point(0, 69);
            this.textBoxScript.Multiline = true;
            this.textBoxScript.Name = "textBoxScript";
            this.textBoxScript.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.textBoxScript.Size = new System.Drawing.Size(568, 227);
            this.textBoxScript.TabIndex = 0;
            this.textBoxScript.TabStop = false;
            this.textBoxScript.WordWrap = false;
            // 
            // undoBtn
            // 
            this.undoBtn.Location = new System.Drawing.Point(178, 301);
            this.undoBtn.Name = "undoBtn";
            this.undoBtn.Size = new System.Drawing.Size(75, 23);
            this.undoBtn.TabIndex = 1;
            this.undoBtn.Text = "Undo";
            this.undoBtn.Click += new System.EventHandler(this.undoBtn_Click);
            // 
            // processBtn
            // 
            this.processBtn.Location = new System.Drawing.Point(273, 301);
            this.processBtn.Name = "processBtn";
            this.processBtn.Size = new System.Drawing.Size(75, 23);
            this.processBtn.TabIndex = 1;
            this.processBtn.Text = "Process";
            this.processBtn.Click += new System.EventHandler(this.processBtn_Click);
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(0, 50);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(100, 16);
            this.label1.TabIndex = 2;
            this.label1.Text = "Script";
            // 
            // label2
            // 
            this.label2.Location = new System.Drawing.Point(0, 328);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(100, 16);
            this.label2.TabIndex = 2;
            this.label2.Text = "Text";
            // 
            // toUpperBtn
            // 
            this.toUpperBtn.Location = new System.Drawing.Point(368, 301);
            this.toUpperBtn.Name = "toUpperBtn";
            this.toUpperBtn.Size = new System.Drawing.Size(75, 23);
            this.toUpperBtn.TabIndex = 1;
            this.toUpperBtn.Text = "ToUpper";
            this.toUpperBtn.Click += new System.EventHandler(this.toUpperBtn_Click);
            // 
            // remoteCheckBox
            // 
            this.remoteCheckBox.Location = new System.Drawing.Point(12, 301);
            this.remoteCheckBox.Name = "remoteCheckBox";
            this.remoteCheckBox.Size = new System.Drawing.Size(120, 24);
            this.remoteCheckBox.TabIndex = 3;
            this.remoteCheckBox.Text = "Unload when done";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.defClasslessButton);
            this.groupBox1.Controls.Add(this.defCapitalizeBtn);
            this.groupBox1.Controls.Add(this.defProcessBtn);
            this.groupBox1.Location = new System.Drawing.Point(273, 12);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(285, 47);
            this.groupBox1.TabIndex = 4;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Scripting mode";
            // 
            // defClasslessButton
            // 
            this.defClasslessButton.AutoSize = true;
            this.defClasslessButton.Location = new System.Drawing.Point(187, 18);
            this.defClasslessButton.Name = "defClasslessButton";
            this.defClasslessButton.Size = new System.Drawing.Size(68, 17);
            this.defClasslessButton.TabIndex = 3;
            this.defClasslessButton.TabStop = true;
            this.defClasslessButton.Text = "Classless";
            this.defClasslessButton.UseVisualStyleBackColor = true;
            this.defClasslessButton.Click += new System.EventHandler(this.defClasslessButton_Click);
            // 
            // defCapitalizeBtn
            // 
            this.defCapitalizeBtn.AutoSize = true;
            this.defCapitalizeBtn.Location = new System.Drawing.Point(103, 18);
            this.defCapitalizeBtn.Name = "defCapitalizeBtn";
            this.defCapitalizeBtn.Size = new System.Drawing.Size(78, 17);
            this.defCapitalizeBtn.TabIndex = 3;
            this.defCapitalizeBtn.TabStop = true;
            this.defCapitalizeBtn.Text = "Capitalizing";
            this.defCapitalizeBtn.UseVisualStyleBackColor = true;
            this.defCapitalizeBtn.Click += new System.EventHandler(this.defCapitalizeBtn_Click);
            // 
            // defProcessBtn
            // 
            this.defProcessBtn.AutoSize = true;
            this.defProcessBtn.Checked = true;
            this.defProcessBtn.Location = new System.Drawing.Point(8, 18);
            this.defProcessBtn.Name = "defProcessBtn";
            this.defProcessBtn.Size = new System.Drawing.Size(77, 17);
            this.defProcessBtn.TabIndex = 2;
            this.defProcessBtn.TabStop = true;
            this.defProcessBtn.Text = "Processing";
            this.defProcessBtn.UseVisualStyleBackColor = true;
            this.defProcessBtn.Click += new System.EventHandler(this.defProcessBtn_Click);
            // 
            // toLowerBtn
            // 
            this.toLowerBtn.Location = new System.Drawing.Point(463, 301);
            this.toLowerBtn.Name = "toLowerBtn";
            this.toLowerBtn.Size = new System.Drawing.Size(75, 23);
            this.toLowerBtn.TabIndex = 1;
            this.toLowerBtn.Text = "ToLower";
            this.toLowerBtn.Click += new System.EventHandler(this.toLowerBtn_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(570, 456);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.remoteCheckBox);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.undoBtn);
            this.Controls.Add(this.textBoxText);
            this.Controls.Add(this.textBoxScript);
            this.Controls.Add(this.processBtn);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.toLowerBtn);
            this.Controls.Add(this.toUpperBtn);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.Name = "Form1";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Text Processor";
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

        private void defCapitalizeBtn_Click(object sender, EventArgs e)
        {
            textBoxScript.Text = capitalizeTemplate;
            remoteCheckBox.Checked = false;
            remoteCheckBox.Enabled = true;
            toUpperBtn.Enabled = true;
            toLowerBtn.Enabled = true;
            processBtn.Enabled = false;
        }

        private void defProcessBtn_Click(object sender, EventArgs e)
        {
            textBoxScript.Text = processTemplate;
            remoteCheckBox.Checked = false;
            remoteCheckBox.Enabled = true;
            toUpperBtn.Enabled = false;
            toLowerBtn.Enabled = false;
            processBtn.Enabled = true;
        }
        
        private void defClasslessButton_Click(object sender, EventArgs e)
        {
            textBoxScript.Text = classlessTemplate;
            remoteCheckBox.Checked = false;
            remoteCheckBox.Enabled = false;
            toUpperBtn.Enabled = false;
            toLowerBtn.Enabled = false;
            processBtn.Enabled = true;
        }

        private void undoBtn_Click(object sender, System.EventArgs e)
        {
            textBoxText.Text = originalText;
        }

        private void processBtn_Click(object sender, System.EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            if (!remoteCheckBox.Checked)
                ExecuteProcessTextLocaly();
            else
                ExecuteProcessTextRemotely();
            Cursor.Current = Cursors.Default;
        }

        private void toUpperBtn_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (remoteCheckBox.Checked)
                {
                    string assemblyFile = CSScript.CompileCode(textBoxScript.Text);

                    //on exit from using assembly will be unloaded and assembly file deleted
                    using (var script = new AsmHelper(assemblyFile, null, true))
                    {
                        var capitalizer = (ITextCapitalizer)script.CreateObject("Script");
                        textBoxText.Text = capitalizer.ToUpper(textBoxText.Text);
                    }
                }
                else
                {
                    Assembly assembly = CSScript.LoadCode(textBoxScript.Text);
                    
                    //using clause is not required as as the assembly will not be unloaded
                    var script = new AsmHelper(assembly); 
                    var capitalizer = (ITextCapitalizer)script.CreateObject("Script");
                    textBoxText.Text = capitalizer.ToUpper(textBoxText.Text);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void toLowerBtn_Click(object sender, EventArgs e)
        {
            try
            {
                if (remoteCheckBox.Checked)
                {
                    string assemblyFile = CSScript.CompileCode(textBoxScript.Text);

                    //on exit from using assembly will be unloaded and assembly file deleted
                    using (var script = new AsmHelper(assemblyFile, null, true))
                    {
                        var capitalizer = (ITextCapitalizer)script.CreateObject("Script");
                        textBoxText.Text = capitalizer.ToLower(textBoxText.Text);
                    }
                }
                else
                {
                    Assembly assembly = CSScript.LoadCode(textBoxScript.Text);

                    //using clause is not required as as the assembly will not be unloaded
                    var script = new AsmHelper(assembly);
                    var capitalizer = (ITextCapitalizer)script.CreateObject("Script");
                    textBoxText.Text = capitalizer.ToLower(textBoxText.Text);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

        void ExecuteProcessTextLocaly()
        {
            try
            {
                if (defClasslessButton.Checked)
                {
                    //script contains only one static method so no need to deal with interfaces, typecasting... 
                    var Process = CSScript.LoadMethod(textBoxScript.Text)
                                          .GetStaticMethod();

                    textBoxText.Text = (string)Process(textBoxText.Text);
                }
                else
                {
                    //We cannot typecase to ITextProcessor as the Script class does not implement it.
                    //But we can use InterfaceAlignment (DuckTyping)
                    ITextProcessor script = CSScript.LoadCode(textBoxScript.Text)
                                                    .CreateObject("Script")
                                                    .AlignToInterface<ITextProcessor>();

                    textBoxText.Text = script.Process(textBoxText.Text);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }
        void ExecuteProcessTextRemotely()
        {
            try
            {
                //Because the script assembly is loaded remotely we must use AsmHelper
                //to perform the InterfaceAlignment (DuckTyping) in the remote AppDomain
                using (AsmHelper helper = new AsmHelper(CSScript.CompileCode(textBoxScript.Text), null, true))
                {
                    ITextProcessor script = helper.CreateAndAlignToInterface<ITextProcessor>("Script");
                    textBoxText.Text = script.Process(textBoxText.Text);
                }
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
    }

    class Script
    {
        static public void Main(string[] args)
        {
            Application.Run(new Form1());
        }
    }
}


